package no.uia.IKT508.XH;

import no.uia.IKT508.XH.XHVariable.State;

import org.alljoyn.bus.BusAttachment;
import org.alljoyn.bus.BusException;
import org.alljoyn.bus.BusObject;
import org.alljoyn.bus.Mutable;
import org.alljoyn.bus.SessionOpts;
import org.alljoyn.bus.SessionPortListener;
import org.alljoyn.bus.SignalEmitter;
import org.alljoyn.bus.Status;

import android.app.Activity;
import android.app.Application;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;

public class XHService{
	static {
		System.loadLibrary("alljoyn_java");
	}
	
	private static final String TAG = "no.uia.IKT508.XH.Service";
	
	private BusAttachment mBus;
	private ChatService mService = new ChatService();
	private XHChatInterface mInterface;
	private ServiceHandler mBusHandler;
	
	private XHListener mListener;
	
	//the well name of service, unique
	private String well_name;
	
	//the name of this device, without name prefix
	private String personalName;
	
	//the port of session initialised by the local service
	private short contactPort;
	
	//the name of joiner
	private String joinerName;
	
	//the session id of the connection
	private int sessionId;
	
	private State state;
	
	private Status status;
	
	
	//initialize the class
	public XHService(XHListener listener)
	{
		this.mListener = listener;
		
		init();
	}
	
	public void init()
	{
		//set the pre-prepared session port
		contactPort = XHVariable.CONTACT_PORT_1;
		
		HandlerThread handlerThread = new HandlerThread("ServiceHandler");
		handlerThread.start();
		mBusHandler = new ServiceHandler(handlerThread.getLooper());
		
		//connect to the bus
		mBusHandler.sendEmptyMessage(XHVariable.CONNECT);
	}
	
	public String getPersonalName()
	{
		return personalName;
	}
	
	//begin to advertise
	public void startAdvertisement(String name)
	{
		Message msg = mBusHandler.obtainMessage(XHVariable.ADVERTISE, name);
		mBusHandler.sendMessage(msg);
	}
	
	
	public void startDisconeect()
	{
		Message msg = mBusHandler.obtainMessage(XHVariable.DISCONNECT);
		mBusHandler.sendMessage(msg);
	}
	
	
	//send the message from the service
	public void startChat(String msg) throws BusException
	{
		mInterface.chat(msg);
	}
	
	//auido talk
	public void startAudio(byte[] sound, int size) throws BusException
	{
		mInterface.audio(sound, size);
	}
	
	//send auido request to the remote client
	public void sendAudioRequest(String start, boolean value, boolean valueRun) throws BusException
	{
		//start the audio track
		mInterface.startAudioTalk(start, value, valueRun);
	}
	
	
	//if the local client has connected to the remote service, change the port to
	//help the service initialise another session
	public void changePort()
	{
		if (XHVariable.CONTACT_PORT_1 == contactPort)
		{
			contactPort = XHVariable.CONTACT_PORT_2;
		}
		else
		{
			contactPort = XHVariable.CONTACT_PORT_1;
		}
	}
	
	
	//the internal handler
	class ServiceHandler extends Handler
	{
		
		public ServiceHandler(Looper looper) {
			super(looper);
		}
		
		@Override
		public void handleMessage(Message msg)
		{
			switch (msg.what)
			{
			case XHVariable.CONNECT:
			{
				doConnect();
				break;
			}
			case XHVariable.ADVERTISE:
			{
				//pass the name
				doAdvertise((String)msg.obj);
				doBindSession();
				break;
			}
			case XHVariable.DISCONNECT:
			{
				doDisconnect();
				break;
			}
			case XHVariable.JOINED:
			{
				//use the signal Emitter to emit the signal
				SignalEmitter emitter = new SignalEmitter(mService, 
														  joinerName, 
														  sessionId, 
														  SignalEmitter.GlobalBroadcast.Off);
				
				mInterface = emitter.getInterface(ChatService.class);
				mListener.OnComplete((String)msg.obj, 0);
				break;
			}
			default:
				break;
			}
		}

		//connect to the bus
		public void doConnect()
		{
			mBus = new BusAttachment(getClass().getName(), BusAttachment.RemoteMessage.Receive);
			
			//register a bus object on the bus attachment
			status = mBus.registerBusObject(mService, XHVariable.OBJECT_PATH);
			if (Status.OK != status)
			{
				XHVariable.logStatus(TAG, "Failed to register a bus object!", status);
				return;
			}
			
			//connect to the bus
			status = mBus.connect();
			if (Status.OK != status)
			{
				XHVariable.logStatus(TAG, "Failed to connect to the bus!", status);
				return;
			}
			
			state = State.ATTACHMENTED;
			
		}
		
		public void doAdvertise(String name)
		{
			int flag = 0;
			personalName = name;
			well_name = XHVariable.NAME_PREFIX + "." + personalName;
			status = mBus.requestName(well_name, flag);
			if (Status.OK != status)
			{
				XHVariable.logStatus(TAG, "Service:requestName()", status);
				return;
			}
			
			status = mBus.advertiseName(well_name, SessionOpts.TRANSPORT_ANY);
			if (Status.OK != status)
			{
				XHVariable.logStatus(TAG, "Service:advertiseName()", status);
				mBus.releaseName(well_name);
				return;
			}
			
			state = State.ADVERTISING;
		}
		
		
		public void doBindSession()
		{
			SessionOpts sessionOpts = new SessionOpts();
			sessionOpts.traffic = SessionOpts.TRAFFIC_MESSAGES;
			sessionOpts.isMultipoint = false;
			sessionOpts.proximity = SessionOpts.PROXIMITY_ANY;
			sessionOpts.transports = SessionOpts.TRANSPORT_BLUETOOTH;
			
			status = mBus.bindSessionPort(new Mutable.ShortValue(contactPort), sessionOpts, new SessionPortListener()
			{
				@Override
				public boolean acceptSessionJoiner(short port, String joiner, SessionOpts opts)
				{
					if (contactPort == port)
					{
						return true;
					}
					else
					{
						return false;
					}
				}
				
				@Override
				public void sessionJoined(short sessionPort, int id, String joiner)
				{
					joinerName = joiner;
					sessionId = id;
					
					//don't execute too long codes in the callback method,
					//use the message to execute them in the handler
					Message msg = mBusHandler.obtainMessage(XHVariable.JOINED, "");
					mBusHandler.sendMessage(msg);
				}
			});
			if (Status.OK != status)
			{
				XHVariable.logStatus(TAG, "Service:bindSessionPort()", status);
				return;
			}
		}
		
		public void doDisconnect()
		{
			mBus.unregisterBusObject(mService);
			mBus.disconnect();
			getLooper().quit();
		}
		
	}
	
	class ChatService implements XHChatInterface, BusObject
	{

		@Override
		public void chat(String msg) throws BusException {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void audio(byte[] sound, int size) throws BusException {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void startAudioTalk(String start, boolean value, boolean valueRun) throws BusException {
			// TODO Auto-generated method stub
			
		}
	}
}
